6-1 おwX

Perl 雖然對文字有強大的處理功能,但若要完整地儲存文字,最方便的方法還是將文字放入資料庫(Databases)。幾乎所有的 UNIX 系統都提供一套稱為 DBM (Database Management) 的標準程式庫,包含了對資料庫的建立、讀取、寫入、刪除等功能,但其資料庫格式是 UNIX 專用格式,並無法和一般資料庫(如 Oracle 或 MS Access)溝通。Perl 本身也支援 DBM 程式庫,因此也可以建立自己專用的資料庫,但由於格式和一般 Win32 資料庫(如 Access、SQL Server、Foxpro)無法溝通,所以較不方便。因此本節重點將以 Perl 如何存取 Win32 的資料庫(如 Microsoft Access、SQL Server等)為主。

基本上,Perl 是經由 ODBC (Open Database Connectivity) 的介面和資料庫溝通。ODBC 是由數個大型資料庫廠商所訂定的標準,其功能就是提供一個完整的應用程式介面(API,Application Program Interface),讓其他應用程式或軟體能夠經由一致的介面來和任何平台、任何支援 ODBC 的資料庫溝通。事實上,Perl 還需要一套模組,才能和 ODBC 溝通,在 Win32 平台上,最常用的模組是 Win32::ODBC,這是由 Dave Roth 所設計的模組,專門讓 Perl 存取 Win32 的資料庫,相關網頁可見:

http://www.roth.net/odbc/
Perl程式碼、Win32::ODBC 模組,以及資料庫 ODBC Driver 的關係可用右圖來表示,其中 Perl 先呼叫 Win32::ODBC 中的各種方法來,Win32 再將相關的 SQL (Strucutre Query Language) 命令送到資料庫的 ODBC Drivers Win32::ODBC 模組具有下列優點: Perl 在和資料庫進行溝通之前,我們必須先設定「資料來源名稱」(Data Source Name,簡稱 DSN),這是一個連接至資料庫的代號,包含下列資訊: DSN 本身又分兩種類別: 欲產生新的 System DSN,可由下列方式來達成:
開始/設定/控制台/ODBC資料來源/系統資料來源名稱/新增
接著選取資料庫類別及位置,依序完成設定即可。若欲產生新的 User DSN,只需將上述的「系統資料來源名稱」改成「使用者資料來源名稱」即可。

一旦設定 DSN 後,即可對資料庫進行讀寫的動作。一般而言,Perl 對資料庫讀寫的動作可以說明如下:

  1. 經由 DSN 和資料庫建立連結
  2. 送出 SQL 命令
  3. 接受並處理 SQL 命令的結果
  4. 重複上述兩步驟,直到存取資料完成
  5. 關閉資料庫連結
建立資料庫連結的典型程式碼如下: $DSN = "Address"; $db = new Win32::ODBC($DSN); # 建立資料庫連結 若 DSN 的設定包含了使用者的帳號和密碼,則上述程式碼應加入帳號和密碼: $DSN = "DSN=Address;UID=Jang;PWD=my_passwd"; $db = new Win32::ODBC($DSN); # 建立資料庫連結 在上述範例中,帳號是「Jang」,密碼是「my_passwd」。

在建立資料庫連結的過程中,若發生錯誤,我們應該印出錯誤訊息,因此上述程式碼的第二列可修改成較完整的寫法,如下:

if (!($db = new Win32::ODBC($dsn))) { print "Error in opening DSN \"$dsn\"!\n"; print "Reason: " . Win32::ODBC::Error(). "\n"; exit; } 請注意在上述程式片段中,若資料庫連結成功,則會回傳一個物件,反之,則會回傳 undef,並將 Win32::ODBC::Error() 傳回的錯誤訊息印出。連結資料庫成功後,接著我們就要送入 SQL 命令,可用 sql() 方法來達成,典型程式碼如下: $sql = "SELECT * FROM table1"; # 選出資料表 table1 中的所有欄位 if ($db->Sql($sql)) { print "Error in SQL query: \"$sql\"!\n"; print "Reason: " . $db->Error() . "\n"; $db->Close(); exit; } 請注意在上述程式碼中,若 SQL 命令執行成功,則 $db->sql($sql) 會回傳 undef,這和前述連結資料庫的回傳意義剛好顛倒。若 SQL 命令執行時發生任何錯誤,$db->Error() 會傳回相關的錯誤訊息。

成功送入 SQL 命令後,接著我們要將回傳資料一筆一筆進行處理,典型程式碼如下:

while ($db->FetchRow()) { %Data = $db->DataHash(); … process result … } 上述 while-迴圈會一再執行,每次成功取得一筆資料時,$db->FetchRow() 即傳回 1,如此依序處理資料,直到所有資料都被處理完畢為止。在每次迴圈中,%Data 會取得每筆資料,並以 hash 的資料型態來儲存此筆資料,其中資料庫的欄位名稱就變成 %Data 的 key,而欄位值就變成 %Data 的 value。若只需要數個欄位,我們可把欄位名稱放入 $db->DataHash 的引數,例如,若只要取得欄位 Name 和 Positoin 的值,可改用下列程式碼: %Data = $db->DataHash("Name", "Position"); 在完成對所有資料的處理後,別忘了要使用下列程式碼來清除和資料庫的連結: $db->Close(); 以下是一個完整的例子,此範例會將 example/test.mdb 的資料庫逐筆印出,在嘗試此範例之前,請記得先要設定 DSN,亦即要將名稱為 AddressBook 的 DSN 設定至資料庫 example/test.mdb。此範例程式碼(listdb1.pl)如下:

原始檔(listdb1.pl):(灰色區域按兩下即可拷貝)
# Display a table in a database using PERL ODBC module

use Win32::ODBC;

$dsn = "AddressBook";
$table = "Namelist";

# ====== Check if the database can be opened correctly
if (!($db = new Win32::ODBC($dsn))) {
	print "Error in opening DSN \"$dsn\"!\n";
	print "Error: " . Win32::ODBC::Error(). "\n";
	exit;
}

# ====== Select all fields from the given table
$sql = "select * from $table;";
$sql = "select * from $table order by Category;";

# ====== Check if the SQL query is correct
if ($db->Sql($sql)) {
	print "Error in SQL query: \"$sql\"!\n";
	print "Error: " . $db->Error() . "\n";
	$db->Close();
	exit;
}

# ====== Print field data
print "Content-type: text/html\n\n";
print "<html><body><pre>\n";
$count = 1;
@FieldNames = $db->FieldNames();
while ($db->FetchRow()) {
	print "Record $count\n";
#	($newsSiteID, $classID) = $db->Data("newsSiteID", "classID");
#	undef %Data;
	%Data = $db->DataHash();
	foreach $x (@FieldNames) {
		print "$x: $Data{$x}\n";
	}
	print "\n";
	$count++;
}
$db->Close();
print "</pre></body></html>\n";

若要新增、刪除或修改資料庫,只要換用不同的 SQL 命令就可以了,請參閱有關 SQL 的章節。

在送入 SQL 命令時,字串欄位值要用單引號刮住,例如:

$sql = "select * from table1 where NAME = 'Roger'"; 但如果是數值欄位,就不需要使用單引號,例如: $sql = "select * from table1 where AGE = 38"; 如果是字串欄位,而且其欄位值還包含單引號,那麼就要使用兩個單引號,例如: $sql = "select * from table1 where NAME = 'Roger''s fish'"; 在上例中,欄位值是「Roger's fish」,將單引號重複一次後,就得到上述的 SQL 命令。

另一個常碰到的問題是:如何使用「|」於欄位值?因為「|」在 SQL 裡面有特殊的意義,因此下面是一個錯誤的寫法:

$sql = "select * from table1 where NAME = 'P|Q'"; 正確的寫法,則是使用「|」的 ASCII 內碼,將 'P|Q' 轉換成 'P' & chr(124) & 'Q',所以正確寫法如下: $sql = "select * from table1 where NAME = 'P' & chr(124) & 'Q'";
Perl